package main

import (
	"fmt"
	"math"
	"sort"
	"time"
)

// 求面积接口
type Areaer interface {
	area() float64
	show() string
}

type shaper struct {
	name string
}

// 圆形
type circularer struct {
	shaper
	radius float64
}

// 圆形构造函数
func newCircular(name string, radius float64) *circularer {
	c := new(circularer)
	c.name = name
	c.radius = radius
	return c

}

// 圆形求面积方法
func (c *circularer) area() float64 {
	return math.Pi * math.Pow(c.radius, 2)
}

func (c *circularer) show() string {
	return c.name
}

// 长方形
type rectangler struct {
	shaper
	length float64
	width  float64
}

// 长方形构造函数
func newRectangler(name string, length, width float64) *rectangler {
	r := new(rectangler)
	r.name = name
	r.length = length
	r.width = width
	return r
}

// 长方形求面积方法
func (r *rectangler) area() float64 {
	return r.length * r.width
}

func (r *rectangler) show() string {
	return r.name
}

// 三角形
type triangler struct {
	shaper
	bottom float64
	hight  float64
}

// 三角形构造函数
func newTriangler(name string, bottom, hight float64) *triangler {
	t := new(triangler)
	t.name = name
	t.bottom = bottom
	t.hight = hight
	return t
}

// 三角形求面积方法
func (t *triangler) area() float64 {
	return t.bottom * t.hight * 0.5
}

func (t *triangler) show() string {
	return t.name
}

// 求面积方法
func getArea(a Areaer) float64 {
	res := a.area()

	return res
}

// 斐波那契数列,使用map方式优化
func fiboByRecord(mapData map[int]int, n int) int {
	if n == 1 || n == 2 {
		return 1
	}
	if _, ok := mapData[n]; ok {
		return mapData[n]
	}
	mapData[n] = fiboByRecord(mapData, n-1) + fiboByRecord(mapData, n-2)
	return mapData[n]
}

func main() {
	// 1、实现对圆形、三角形、长方形求面积。
	// 实例化三角形、长方形、圆形
	circ := newCircular("circle", 2)
	rec := newRectangler("rec", 4, 3)
	tri := newTriangler("tri", 10, 5)

	//求面积
	cres := getArea(circ)
	recres := getArea(rec)
	trires := getArea(tri)
	fmt.Println("圆形", cres)
	fmt.Println("长方形", recres)
	fmt.Println("三角形", trires)

	// 2、利用第1题，构造3个以上图形，至少圆形、三角形、矩形各有一个，对上题的图形按照面积降序排列。
	areas := make([]Areaer, 0, 3)
	areas = append(areas, circ, rec, tri)
	sort.Slice(areas, func(i, j int) bool {
		return areas[i].area() > areas[j].area()
	})

	// 降序输出
	for _, a := range areas {
		fmt.Println(a.show())
	}

	//3、分析斐波那契数列递推公式递归版本的问题，试着为该函数提供一个Cache，使其计算效率提升
	// start2 := time.Now().UnixNano()
	// var mapData = make(map[int]int, 0)
	// res := fiboByRecord(mapData, 30)
	// fmt.Println(res)
	// end2 := time.Now().UnixNano()
	// fmt.Println("run Time:", end2-start2)

	//4、8年前的今天上午9点30分
	/*
		要求：
		1. 毫秒时间戳是多少？
		2. 格式化输出时间为 2005/09/10 21:35:40 +0800 的形式
		3. 请问那天是周几？到那天，本年已经过了多少周？
		4. 距离今天已经过了多少天了？
	*/
	now := time.Now()           //获取当前时间
	year := now.Year() - int(8) //年
	month := int(now.Month())   //月 march
	day := now.Day()            //日
	// fmt.Println(year, month, day)

	//拼接字符串
	btime := fmt.Sprintf("%04d/%02d/%02d %02d:%02d:%02d", year, month, day, 9, 30, 0)
	// fmt.Println(btime)
	//将字符串转换成时间对象
	// 加载时区
	loc, err := time.LoadLocation("Asia/Shanghai")
	if err != nil {
		fmt.Println(err)
		return
	}
	// 按照指定时区和指定格式解析字符串时间
	timeObj, err := time.ParseInLocation("2006/01/02 15:04:05", btime, loc)
	if err != nil {
		fmt.Println(err)
		return
	}
	// 格式化输出时间为 2005/09/10 21:35:40 +0800 的形式
	fmt.Println(timeObj.Format("2006/01/02 15:04:05 -0700"))
	// 毫秒时间戳是
	fmt.Println(timeObj.UnixNano())
	// 请问那天是周几？到那天，本年已经过了多少周？
	fmt.Println(timeObj.Weekday())
	fmt.Println(timeObj.ISOWeek())
	//距离今天已经过了多少天
	diff := (now.UnixNano() - timeObj.UnixNano())
	fmt.Println(diff / 1000000000 / 60 / 60 / 24) //天
}

